package com.security.config;

import com.security.customer.access.CustomerDecideManager;
import com.security.customer.filter.CustomerAccessSecurityInterceptor;
import com.security.customer.filter.ValidateCodeAuthenticationFilter;
import com.security.customer.handler.CustomerAccessDeniedHandler;
import com.security.customer.metadata.CustomerPermissionMetadataSource;
import com.security.customer.mobile.SmsCodeAuthenticationConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @Author: TongRui乀
 * @Date: 2020/3/21 8:38
 * @description：  SpringSecurity 的安全配置  配置登录方式、认证逻辑、结果处理器、拦截路径等
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     *  表单登录 成功的处理逻辑
     */
    @Autowired
    private AuthenticationSuccessHandler customerUsernamePasswordLoginSuccessHandler;

    /**
     *  表单登录 失败的处理逻辑
     */
    @Autowired
    private AuthenticationFailureHandler customerUsernamePasswordLoginFailureHandler;

    @Autowired
    private ValidateCodeAuthenticationFilter validateCodeAuthenticationFilter;

    @Autowired
    private UserDetailsService customerUserDetailService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private SmsCodeAuthenticationConfig smsCodeAuthenticationConfig;

    @Autowired
    private CustomerAccessDeniedHandler customerAccessDeniedHandler;


//    @Autowired
//    private CustomerAccessSecurityInterceptor customerAccessSecurityInterceptor;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .addFilterBefore(validateCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)//添加一个自定义的认证过滤器
            .formLogin()  // 指定通过表单方式登录 也就是 用户名密码登录
                .loginPage("/authentication/loginHandler")// 指定登录页面或指定一个controller
                .loginProcessingUrl("/authentication/form") // 指定登录的接口
                .usernameParameter("username")// 指定用户名的字段名
                .passwordParameter("password")
                .successHandler(customerUsernamePasswordLoginSuccessHandler) // 认证成功处理器
                .failureHandler(customerUsernamePasswordLoginFailureHandler) // 认证失败处理器
                .and()
                .apply(smsCodeAuthenticationConfig) // 短信验证码登陆流程
//                .and() // 记住我功能
//            .rememberMe()
//                .tokenRepository(persistentTokenRepository(dataSource))
//                .tokenValiditySeconds(3600)
//                .userDetailsService(customerUserDetailService)
            .and().authorizeRequests()
                .antMatchers("/imooc-signIn.html"  // 登录页
                                        , "/authentication/**" // 认证跳转的接口
                                        , "/verification/**"
                                        , "/favicon.icon"
                                        ).permitAll()

                .anyRequest()
//                .access("@permissionServiceImpl.hasPermission(request,authentication)")//  所有请求必须通过我们的自定义的权限校验
                .authenticated()// 所有请求都必须认证
                .and()
                .exceptionHandling()
                .accessDeniedHandler(customerAccessDeniedHandler) // 认证失败处理器
            .and().csrf().disable();

        // 添加权限验证
//        http.addFilterBefore(customerAccessSecurityInterceptor, FilterSecurityInterceptor.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customerUserDetailService).passwordEncoder(passwordEncoder());
    }

    /**
     *  密码加密方式
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     *  记住我功能设置 TokenRepository
     * @param dataSource
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository(DataSource dataSource){
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();

        repository.setDataSource(dataSource);
        // 自动创建记住我的表  执行一次即可
//        repository.setCreateTableOnStartup(true);

        return repository;
    }

}
